package com.rd.animation.type;

import com.rd.animation.controller.ValueController;
import com.rd.animation.data.type.WormAnimationValue;
import com.rd.utils.AnimatorUtils;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorValue;

public class WormAnimation extends BaseAnimation<AnimatorGroup> {
    int coordinateStart;
    int coordinateEnd;

    int radius;
    boolean isRightSide;

    int rectLeftEdge;
    int rectRightEdge;

    private WormAnimationValue value;

    public WormAnimation(ValueController.UpdateListener listener) {
        super(listener);
        value = new WormAnimationValue();
    }

    @Override
    public AnimatorGroup createAnimator() {
        AnimatorGroup animator = new AnimatorGroup();
        animator.setCurveType(Animator.CurveType.ACCELERATE_DECELERATE);
        return animator;
    }

    @Override
    public WormAnimation duration(long duration) {
        super.duration(duration);
        return this;
    }

    public WormAnimation with(int coordinateStart, int coordinateEnd, int radius, boolean isRightSide) {
        if (hasChanges(coordinateStart, coordinateEnd, radius, isRightSide)) {
            animator = createAnimator();

            this.coordinateStart = coordinateStart;
            this.coordinateEnd = coordinateEnd;

            this.radius = radius;
            this.isRightSide = isRightSide;

            rectLeftEdge = coordinateStart - radius;
            rectRightEdge = coordinateStart + radius;

            value.setRectStart(rectLeftEdge);
            value.setRectEnd(rectRightEdge);

            RectValues rect = createRectValues(isRightSide);
            long duration = animationDuration / 2;

            AnimatorValue straightAnimator = createWormAnimator(rect.fromX, rect.toX, duration, false, value);
            AnimatorValue reverseAnimator =
                    createWormAnimator(rect.reverseFromX, rect.reverseToX, duration, true, value);
            animator.runSerially(straightAnimator, reverseAnimator);
        }
        return this;
    }

    @Override
    public WormAnimation progress(float progress) {
        if (animator == null) {
            return this;
        }

        long progressDuration = (long) (progress * animationDuration);
        for (Animator anim : animator.getAnimatorsAt(0)) {
            ValueAnimator animator = (ValueAnimator) anim;
            long duration = animator.getDuration();
            long setDuration = progressDuration;

            if (setDuration > duration) {
                setDuration = duration;
            }

            //            animator.setCurrentPlayTime(setDuration);
            float v = AnimatorUtils.getInterpolation(progress);
            animator.onUpdate(animator, v);
            onAnimateUpdated(value, animator, animator.isReverse());
            progressDuration -= setDuration;
        }

        return this;
    }

    ValueAnimator createWormAnimator(
            int fromValue, int toValue, long duration, final boolean isReverse, final WormAnimationValue value) {
        ValueAnimator anim = new ValueAnimator();
        anim.setCurveType(Animator.CurveType.ACCELERATE_DECELERATE);
        anim.setDuration(duration);
        anim.setInnerListener(
                new InnerValueUpdateListener() {
                    @Override
                    public void onUpdate(AnimatorValue animatorValue, float f) {
                        rectEdge = AnimatorUtils.getIntValue(fromValue, toValue, f);
                    }
                });
        anim.setValueUpdateListener(
                new AnimatorValue.ValueUpdateListener() {
                    @Override
                    public void onUpdate(AnimatorValue animatorValue, float v) {
                        anim.onUpdate(animatorValue, v);
                        onAnimateUpdated(value, animatorValue, isReverse);
                    }
                });

        return anim;
    }

    int rectEdge;

    private void onAnimateUpdated(WormAnimationValue value, AnimatorValue animation, final boolean isReverse) {
        if (isRightSide) {
            if (!isReverse) {
                value.setRectEnd(rectEdge);
            } else {
                value.setRectStart(rectEdge);
            }

        } else {
            if (!isReverse) {
                value.setRectStart(rectEdge);
            } else {
                value.setRectEnd(rectEdge);
            }
        }

        if (listener != null) {
            listener.onValueUpdated(value);
        }
    }

    @SuppressWarnings("RedundantIfStatement")
    boolean hasChanges(int coordinateStart, int coordinateEnd, int radius, boolean isRightSide) {
        if (this.coordinateStart != coordinateStart) {
            return true;
        }

        if (this.coordinateEnd != coordinateEnd) {
            return true;
        }

        if (this.radius != radius) {
            return true;
        }

        if (this.isRightSide != isRightSide) {
            return true;
        }

        return false;
    }

    RectValues createRectValues(boolean isRightSide) {
        int fromX;
        int toX;

        int reverseFromX;
        int reverseToX;

        if (isRightSide) {
            fromX = coordinateStart + radius;
            toX = coordinateEnd + radius;

            reverseFromX = coordinateStart - radius;
            reverseToX = coordinateEnd - radius;

        } else {
            fromX = coordinateStart - radius;
            toX = coordinateEnd - radius;

            reverseFromX = coordinateStart + radius;
            reverseToX = coordinateEnd + radius;
        }

        return new RectValues(fromX, toX, reverseFromX, reverseToX);
    }

    class RectValues {
        final int fromX;
        final int toX;

        final int reverseFromX;
        final int reverseToX;

        RectValues(int fromX, int toX, int reverseFromX, int reverseToX) {
            this.fromX = fromX;
            this.toX = toX;

            this.reverseFromX = reverseFromX;
            this.reverseToX = reverseToX;
        }
    }
}
